package com.service;


import com.google.common.collect.ImmutableList;
import org.eclipse.milo.opcua.sdk.client.OpcUaClient;
import org.eclipse.milo.opcua.stack.core.AttributeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.enumerated.MonitoringMode;
import org.eclipse.milo.opcua.stack.core.types.enumerated.TimestampsToReturn;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoredItemCreateRequest;
import org.eclipse.milo.opcua.stack.core.types.structured.MonitoringParameters;
import org.eclipse.milo.opcua.stack.core.types.structured.ReadValueId;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Linjiapeng
 * @date 2023.11.13
 * 连续获取服务器中北区的全部数据
 */
@Service("serviceFunction")
public class ServiceFunctionImpl implements ServiceFunction {


    public void doSomething(OpcUaClient client) {
        return;
    }

    /**
     * 获取二期发电数据（三、四号机组），保存到数据库中
     *
     * @return
     */
    @Override
    public void doSomething(OpcUaClient client, CompletableFuture<OpcUaClient> future) throws Exception {
        System.out.println("####获取数据（x.1和x.2）");
        readTagData(client).thenAccept(values -> {
            DataValue nodeId_Tag1 = values.get(0);
            DataValue nodeId_Tag2 = values.get(1);
            System.out.println("#########x1=" + nodeId_Tag1.getValue().getValue());
            System.out.println("#########x2=" + nodeId_Tag2.getValue().getValue());
            //如果开启订阅，需要把这一行注销掉，因为，这一行会将future完成,然后将client连接关掉。
            future.complete(client);
        });

        //删除注释开始订阅功能
        //subscribe(client);

    }
    private CompletableFuture<List<DataValue>> readTagData(OpcUaClient client) {
        NodeId nodeId_Tag1 = new NodeId(2,"my.device.x1");
        NodeId nodeId_Tag2 = new NodeId(2, "my.device.x2");

        List<NodeId> nodeIds = ImmutableList.of(nodeId_Tag1, nodeId_Tag2);
        return client.readValues(0.0, TimestampsToReturn.Both, nodeIds);
    }
    private  void subscribe(OpcUaClient client) throws Exception {
        AtomicInteger atomic = new AtomicInteger(1);

        //创建发布间隔1000ms的订阅对象
        client
                .getSubscriptionManager()
                .createSubscription(1000.0)
                .thenAccept(t -> {
                    //节点1
                    NodeId nodeId1 = new NodeId(2,"my.device.x1");
                    ReadValueId readValueId1 = new ReadValueId(nodeId1, AttributeId.Value.uid(), null, null);
                    //节点2
                    NodeId nodeId2 = new NodeId(2,"my.device.x2");
                    ReadValueId readValueId2 = new ReadValueId(nodeId2, AttributeId.Value.uid(), null, null);

                    //创建监控的参数
                    MonitoringParameters parameters = new MonitoringParameters(UInteger.valueOf(atomic.getAndIncrement()), 1000.0, null, UInteger.valueOf(10), true);

                    //创建监控项请求
                    //该请求最后用于创建订阅。
                    MonitoredItemCreateRequest request1 = new MonitoredItemCreateRequest(readValueId1, MonitoringMode.Reporting, parameters);
                    MonitoredItemCreateRequest request2 = new MonitoredItemCreateRequest(readValueId2, MonitoringMode.Reporting, parameters);

                    List<MonitoredItemCreateRequest> requests = new ArrayList<>();
                    requests.add(request1);
                    requests.add(request2);

                    //创建监控项，并且注册变量值改变时候的回调函数。
                    t.createMonitoredItems(
                            TimestampsToReturn.Both,
                            requests,
                            (item, id) -> item.setValueConsumer((it, val) -> {
                                System.out.println("标识为" + it.getReadValueId().getNodeId()+"的项的值被更新为："+ val.getValue().getValue());
                            })
                    );
                }).get();

        //持续订阅
        Thread.sleep(Long.MAX_VALUE);
    }


}